package com.hongshu.idle.service.idle.impl;

import cn.hutool.core.collection.CollectionUtil;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.query_dsl.BoolQuery;
import co.elastic.clients.elasticsearch.core.*;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.elasticsearch.core.search.TotalHits;
import com.alibaba.nacos.shaded.com.google.common.collect.Lists;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hongshu.common.core.constant.NoteConstant;
import com.hongshu.common.core.enums.AuditStatusEnum;
import com.hongshu.common.core.exception.HongshuException;
import com.hongshu.common.core.utils.bean.BeanUtils;
import com.hongshu.idle.auth.AuthContextHolder;
import com.hongshu.idle.domain.dto.EsProductDTO;
import com.hongshu.idle.domain.dto.SystemConfigDTO;
import com.hongshu.idle.domain.entity.IdleProduct;
import com.hongshu.idle.domain.vo.IdleProductVO;
import com.hongshu.idle.mapper.idle.IdleProductMapper;
import com.hongshu.idle.service.IRecommendProductService;
import com.hongshu.idle.service.idle.IIdleEsProductService;
import com.hongshu.idle.service.sys.ISysSystemConfigService;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * ES
 *
 * @author: hongshu
 */
@Service
@Slf4j
public class IdleEsProductServiceImpl extends ServiceImpl<IdleProductMapper, IdleProduct> implements IIdleEsProductService {

    @Autowired
    private IRecommendProductService recommendService;
    @Autowired
    private ElasticsearchClient elasticsearchClient;
    @Autowired
    private ISysSystemConfigService systemConfigService;
    @Autowired
    private IdleProductMapper productMapper;


    /**
     * 搜索对应的商品
     *
     * @param currentPage  当前页
     * @param pageSize     分页数
     * @param esProductDTO 笔记
     */
    @Override
    public Page<IdleProductVO> getProductByDTO(long currentPage, long pageSize, EsProductDTO esProductDTO) {
        Page<IdleProductVO> page = new Page<>();

        SystemConfigDTO systemConfig = systemConfigService.getSystemConfig();
        String queryPrimary = systemConfig.getQueryPrimary();

        // ES检索
        if ("es".equals(queryPrimary)) {
            return getProductByDTOFromES(currentPage, pageSize, esProductDTO);
        }
        // MySQL检索
        else if ("mysql".equals(queryPrimary)) {
            return getProductByDTOFromMysql(currentPage, pageSize, esProductDTO);
        }

        return page;
//        Page<IdleProductVO> page = new Page<>();
//        List<IdleProductVO> idleProductVOList = new ArrayList<>();
//        try {
//            SearchRequest.Builder builder = new SearchRequest.Builder().index(NoteConstant.PRODUCT_INDEX);
//            if (StringUtils.isNotBlank(esProductDTO.getKeyword())) {
//                builder.query(q -> q.bool(b -> b
//                        .should(h -> h.match(f -> f.field("title").boost(1f).query(esProductDTO.getKeyword())))
//                        .should(h -> h.match(f -> f.field("username").boost(0.5f).query(esProductDTO.getKeyword())))
//                        .should(h -> h.match(f -> f.field("content").boost(1f).query(esProductDTO.getKeyword())))
//                        .should(h -> h.match(f -> f.field("tags").boost(4f).query(esProductDTO.getKeyword())))
//                        .should(h -> h.match(f -> f.field("categoryName").boost(2f).query(esProductDTO.getKeyword())))
//                        .should(h -> h.match(f -> f.field("categoryParentName").boost(1.5f).query(esProductDTO.getKeyword())))
//                ));
//            }
//            if (StringUtils.isNotBlank(esProductDTO.getCpid()) && StringUtils.isNotBlank(esProductDTO.getCid())) {
//                builder.query(q -> q.bool(b -> b
//                        .must(h -> h.match(m -> m.field("cid").query(esProductDTO.getCid())))
//                        .must(h -> h.match(m -> m.field("cpid").query(esProductDTO.getCpid())))
//                ));
//            } else if (StringUtils.isNotBlank(esProductDTO.getCpid())) {
//                builder.query(h -> h.match(m -> m.field("cpid").query(esProductDTO.getCpid())));
//                builder.sort(h -> h.field(m -> m.field("time").order(SortOrder.Desc)));
//            }
//
//            if (esProductDTO.getType() == 1) {
//                builder.sort(o -> o.field(f -> f.field("likeCount").order(SortOrder.Desc)));
//            } else if (esProductDTO.getType() == 2) {
//                builder.sort(o -> o.field(f -> f.field("time").order(SortOrder.Desc)));
//            }
//            builder.from((int) (currentPage - 1) * (int) pageSize);
//            builder.size((int) pageSize);
//            SearchRequest searchRequest = builder.build();
//            SearchResponse<IdleProductVO> searchResponse = elasticsearchClient.search(searchRequest, IdleProductVO.class);
//            TotalHits totalHits = searchResponse.hits().total();
//            page.setTotal(Objects.requireNonNull(totalHits).value());
//            page.setCountId(esProductDTO.getCpid());
//            List<Hit<IdleProductVO>> hits = searchResponse.hits().hits();
//            for (Hit<IdleProductVO> hit : hits) {
//                IdleProductVO idleProductVO = hit.source();
//                idleProductVOList.add(idleProductVO);
//            }
//        } catch (Exception e) {
//            e.printStackTrace();
//            throw new HongshuException("es查找数据异常");
//        }
//        page.setRecords(idleProductVOList);
//        return page;
    }

    /**
     * 从ES搜索商品
     */
    private Page<IdleProductVO> getProductByDTOFromES(long currentPage, long pageSize, EsProductDTO esProductDTO) {
        Page<IdleProductVO> page = new Page<>();
        List<IdleProductVO> idleProductVOList = new ArrayList<>();
        try {
            SearchRequest.Builder builder = new SearchRequest.Builder().index(NoteConstant.PRODUCT_INDEX);
            // 构建bool查询
            BoolQuery.Builder boolBuilder = new BoolQuery.Builder();
            // 关键词搜索
            if (StringUtils.isNotBlank(esProductDTO.getKeyword())) {
                boolBuilder.must(m -> m.bool(bb -> bb
                        .should(h -> h.match(f -> f.field("title").boost(1f).query(esProductDTO.getKeyword())))
                        .should(h -> h.match(f -> f.field("username").boost(0.5f).query(esProductDTO.getKeyword())))
                        .should(h -> h.match(f -> f.field("content").boost(1f).query(esProductDTO.getKeyword())))
                        .should(h -> h.match(f -> f.field("tags").boost(4f).query(esProductDTO.getKeyword())))
                        .should(h -> h.match(f -> f.field("categoryName").boost(2f).query(esProductDTO.getKeyword())))
                        .should(h -> h.match(f -> f.field("categoryParentName").boost(1.5f).query(esProductDTO.getKeyword())))
                ));
            }
            // 分类条件
            if (StringUtils.isNotBlank(esProductDTO.getCpid()) && StringUtils.isNotBlank(esProductDTO.getCid())) {
                boolBuilder.must(h -> h.match(m -> m.field("cid").query(esProductDTO.getCid())));
                boolBuilder.must(h -> h.match(m -> m.field("cpid").query(esProductDTO.getCpid())));
            } else if (StringUtils.isNotBlank(esProductDTO.getCpid())) {
                boolBuilder.must(h -> h.match(m -> m.field("cpid").query(esProductDTO.getCpid())));
            }
            // 设置查询
            builder.query(q -> q.bool(boolBuilder.build()));
            // 排序
            if (esProductDTO.getType() == 1) {
                builder.sort(o -> o.field(f -> f.field("likeCount").order(SortOrder.Desc)));
            } else if (esProductDTO.getType() == 2) {
                builder.sort(o -> o.field(f -> f.field("time").order(SortOrder.Desc)));
            } else {
                builder.sort(h -> h.field(m -> m.field("time").order(SortOrder.Desc)));
            }
            builder.from((int) (currentPage - 1) * (int) pageSize);
            builder.size((int) pageSize);

            SearchRequest searchRequest = builder.build();
            SearchResponse<IdleProductVO> searchResponse = elasticsearchClient.search(searchRequest, IdleProductVO.class);
            TotalHits totalHits = searchResponse.hits().total();
            page.setTotal(Objects.requireNonNull(totalHits).value());
            page.setCountId(esProductDTO.getCpid());
            List<Hit<IdleProductVO>> hits = searchResponse.hits().hits();
            for (Hit<IdleProductVO> hit : hits) {
                IdleProductVO idleProductVO = hit.source();
                idleProductVOList.add(idleProductVO);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new HongshuException("es查找数据异常");
        }
        page.setRecords(idleProductVOList);
        return page;
    }

    /**
     * 从MySQL搜索商品
     */
    private Page<IdleProductVO> getProductByDTOFromMysql(long currentPage, long pageSize, EsProductDTO esProductDTO) {
        Page<IdleProductVO> page = new Page<>();
        // 构建查询条件
        QueryWrapper<IdleProduct> queryWrapper = new QueryWrapper<IdleProduct>()
                .eq("status", "PUBLISHED") // 假设已发布的商品状态
                .eq("audit_status", "APPROVED"); // 假设审核通过的商品状态
        // 关键词搜索
        if (StringUtils.isNotBlank(esProductDTO.getKeyword())) {
            queryWrapper.and(wrapper -> wrapper
                    .like("title", esProductDTO.getKeyword())
                    .or().like("content", esProductDTO.getKeyword())
                    .or().like("tags", esProductDTO.getKeyword())
                    .or().like("username", esProductDTO.getKeyword())
            );
        }
        // 分类条件
        if (StringUtils.isNotBlank(esProductDTO.getCpid()) && StringUtils.isNotBlank(esProductDTO.getCid())) {
            queryWrapper.eq("cpid", esProductDTO.getCpid())
                    .eq("cid", esProductDTO.getCid());
        } else if (StringUtils.isNotBlank(esProductDTO.getCpid())) {
            queryWrapper.eq("cpid", esProductDTO.getCpid());
        }
        // 排序
        if (esProductDTO.getType() == 1) {
            // 按点赞数排序
            queryWrapper.orderByDesc("like_count");
        } else if (esProductDTO.getType() == 2) {
            // 按时间排序
            queryWrapper.orderByDesc("time");
        } else {
            // 默认按时间排序
            queryWrapper.orderByDesc("time");
        }

        // 执行分页查询
        Page<IdleProduct> productPage = productMapper.selectPage(new Page<>(currentPage, pageSize), queryWrapper);
        // 转换结果
        page.setCurrent(productPage.getCurrent());
        page.setSize(productPage.getSize());
        page.setTotal(productPage.getTotal());
        page.setCountId(esProductDTO.getCpid());
        page.setRecords(productPage.getRecords().stream()
                .map(this::convertToProductVO)
                .collect(Collectors.toList()));
        return page;
    }

    /**
     * 获取推荐商品
     *
     * @param currentPage 当前页
     * @param pageSize    分页数
     */
    @SneakyThrows
    @Override
    public Page<IdleProductVO> getRecommendProduct(long currentPage, long pageSize) {
        Page<IdleProductVO> page = new Page<>();

        SystemConfigDTO systemConfig = systemConfigService.getSystemConfig();
        String queryPrimary = systemConfig.getQueryPrimary();

        // ES检索
        if ("es".equals(queryPrimary)) {
            return getRecommendProductFromES(currentPage, pageSize);
        }
        // MySQL检索
        else if ("mysql".equals(queryPrimary)) {
            return getRecommendProductFromMysql(currentPage, pageSize);
        }

        return page;
//        Page<IdleProductVO> page = new Page<>();
//
//        SystemConfigDTO systemConfig = systemConfigService.getSystemConfig();
//        String queryPrimary = systemConfig.getQueryPrimary();
//        // ES检索
//        if ("es".equals(queryPrimary)) {
//            String userId = AuthContextHolder.getUserId();
//            List<IdleProductVO> recommendList;
//            // 用户ID为空 默认随机加载100条数据
//            if (StringUtils.isBlank(userId)) {
//                SearchRequest searchRequest = SearchRequest.of(s -> s
//                        .index(NoteConstant.PRODUCT_INDEX)
//                        .size(100));
//                SearchResponse<IdleProductVO> searchResponse = elasticsearchClient.search(searchRequest, IdleProductVO.class);
//                recommendList = searchResponse.hits().hits().stream()
//                        .map(Hit::source)
//                        .collect(Collectors.toList());
//                // 随机排序
//                Collections.shuffle(recommendList, new Random());
//            } else {
//                // 获取推荐列表
//                recommendList = recommendService.getRecommendProduct(Long.parseLong(userId));
//            }
//            List<List<IdleProductVO>> partition = Lists.partition(recommendList, (int) pageSize);
//            // 如果 currentPage 超出范围，返回空记录
//            if (currentPage > partition.size() || currentPage <= 0) {
//                page.setTotal(0);
//                page.setRecords(Collections.emptyList());
//                return page;
//            }
//            List<IdleProductVO> idleProductVOList = partition.get((int) currentPage - 1);
//            page.setTotal(recommendList.size());
//            page.setRecords(idleProductVOList);
//            return page;
//        }
//        // MySQL检索
//        else if ("mysql".equals(queryPrimary)) {
//            String userId = AuthContextHolder.getUserId();
//            if (StringUtils.isBlank(userId)) {
//                // 用户未登录，随机获取100条公开笔记
//                List<IdleProductVO> randomProducts = productMapper.selectList(
//                                new QueryWrapper<IdleProduct>()
//                                        .eq("audit_status", AuditStatusEnum.PASS.getCode())
//                                        .orderBy(true, false, "RAND()")
//                                        .last("LIMIT " + 100)
//                        ).stream()
//                        .map(this::convertToProductVO)
//                        .collect(Collectors.toList());
//                // 随机排序
//                Collections.shuffle(randomProducts, new Random());
//                // 分页处理
//                List<List<IdleProductVO>> partition = Lists.partition(randomProducts, (int) pageSize);
//                if (currentPage > partition.size() || currentPage <= 0) {
//                    page.setTotal(0);
//                    page.setRecords(Collections.emptyList());
//                    return page;
//                }
//                List<IdleProductVO> noteSearchVos = partition.get((int) currentPage - 1);
//                page.setTotal(randomProducts.size());
//                page.setRecords(noteSearchVos);
//            } else {
//                // 用户已登录，通过推荐算法获取推荐列表
//                page = recommendService.getRecommendProductFromMysql(userId, currentPage, pageSize);
//            }
//            return page;
//        }
//        return page;
    }

    /**
     * 从ES获取推荐商品
     */
    private Page<IdleProductVO> getRecommendProductFromES(long currentPage, long pageSize) {
        String userId = AuthContextHolder.getUserId();
        List<IdleProductVO> recommendList;

        if (StringUtils.isBlank(userId)) {
            // 用户未登录，随机获取100条数据
            recommendList = getRandomProductsFromES(100);
        } else {
            // 用户已登录，通过推荐算法获取推荐列表
            recommendList = recommendService.getRecommendProduct(Long.parseLong(userId));
        }

        return buildProductPageFromList(recommendList, currentPage, pageSize);
    }

    /**
     * 从MySQL获取推荐商品
     */
    private Page<IdleProductVO> getRecommendProductFromMysql(long currentPage, long pageSize) {
        String userId = AuthContextHolder.getUserId();

        if (StringUtils.isBlank(userId)) {
            // 用户未登录，随机获取100条公开商品
            List<IdleProductVO> randomProducts = getRandomProductsFromMysql(100);
            return buildProductPageFromList(randomProducts, currentPage, pageSize);
        } else {
            // 用户已登录，通过推荐算法获取推荐列表
            return recommendService.getRecommendProductFromMysql(userId, currentPage, pageSize);
        }
    }

    /**
     * 从ES随机获取指定数量的商品
     */
    private List<IdleProductVO> getRandomProductsFromES(int limit) {
        SearchRequest searchRequest = SearchRequest.of(s -> s
                .index(NoteConstant.PRODUCT_INDEX)
                .size(limit));
        SearchResponse<IdleProductVO> searchResponse = null;
        try {
            searchResponse = elasticsearchClient.search(searchRequest, IdleProductVO.class);
        } catch (IOException e) {
            e.printStackTrace();
        }
        List<IdleProductVO> recommendList = searchResponse.hits().hits().stream()
                .map(Hit::source)
                .collect(Collectors.toList());
        // 随机排序
        Collections.shuffle(recommendList, new Random());
        return recommendList;
    }

    /**
     * 从MySQL随机获取指定数量的公开商品
     */
    private List<IdleProductVO> getRandomProductsFromMysql(int limit) {
        List<IdleProductVO> randomProducts = productMapper.selectList(
                        new QueryWrapper<IdleProduct>()
                                .eq("audit_status", AuditStatusEnum.PASS.getCode())
                                .orderBy(true, false, "RAND()")
                                .last("LIMIT " + limit)
                ).stream()
                .map(this::convertToProductVO)
                .collect(Collectors.toList());
        // 随机排序
        Collections.shuffle(randomProducts, new Random());
        return randomProducts;
    }

    /**
     * 从商品列表构建分页结果
     */
    private Page<IdleProductVO> buildProductPageFromList(List<IdleProductVO> productList, long currentPage, long pageSize) {
        Page<IdleProductVO> page = new Page<>();
        List<List<IdleProductVO>> partition = Lists.partition(productList, (int) pageSize);

        // 如果 currentPage 超出范围，返回空记录
        if (currentPage > partition.size() || currentPage <= 0) {
            page.setTotal(0);
            page.setRecords(Collections.emptyList());
            return page;
        }

        List<IdleProductVO> idleProductVOList = partition.get((int) currentPage - 1);
        page.setTotal(productList.size());
        page.setRecords(idleProductVOList);
        return page;
    }

    private IdleProductVO convertToProductVO(IdleProduct product) {
        IdleProductVO vo = new IdleProductVO();
        BeanUtils.copyProperties(product, vo);
        return vo;
    }

    /**
     * 获取热榜笔记
     *
     * @param currentPage 当前页
     * @param pageSize    分页数
     */
    @Override
    public Page<IdleProductVO> getHotProduct(long currentPage, long pageSize) {
        Page<IdleProductVO> page = new Page<>(currentPage, pageSize);
        List<IdleProductVO> idleProductVOList = new ArrayList<>();

        try {
            // 构建搜索请求
            SearchRequest.Builder builder = new SearchRequest.Builder()
                    .index(NoteConstant.PRODUCT_INDEX)
                    .from(Math.toIntExact((currentPage - 1) * pageSize)) // 设置分页起始点
                    .size(Math.toIntExact(pageSize)) // 设置分页大小
                    .sort(s -> s.field(f -> f.field("likeCount").order(SortOrder.Desc))); // 按 likeCount 降序排序

            SearchRequest searchRequest = builder.build();

            // 执行搜索请求
            SearchResponse<IdleProductVO> searchResponse = elasticsearchClient.search(searchRequest, IdleProductVO.class);
            TotalHits totalHits = searchResponse.hits().total();

            // 获取搜索结果
            List<Hit<IdleProductVO>> hits = searchResponse.hits().hits();
            if (CollectionUtil.isNotEmpty(hits)) {
                for (Hit<IdleProductVO> hit : hits) {
                    IdleProductVO idleProductVO = hit.source();
                    idleProductVOList.add(idleProductVO);
                }
            }

            // 设置分页结果
            page.setTotal(totalHits != null ? totalHits.value() : 0);
            page.setRecords(idleProductVOList);

        } catch (Exception e) {
            e.printStackTrace();
            // 这里可以进一步处理异常，比如记录日志或者抛出自定义异常
        }
        return page;
    }


    /**
     * 增加笔记
     *
     * @param idleProductVO 笔记
     */
    @Override
    public void addProduct(IdleProductVO idleProductVO) {
        try {
            CreateResponse createResponse = elasticsearchClient
                    .create(e -> e.index(NoteConstant.PRODUCT_INDEX).id(idleProductVO.getId()).document(idleProductVO));
            log.info("createResponse.result{}", createResponse.result());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 修改笔记
     *
     * @param idleProductVO 笔记
     */
    @Override
    public void updateProduct(IdleProductVO idleProductVO) {
        try {
            UpdateResponse<IdleProductVO> updateResponse = elasticsearchClient
                    .update(e -> e.index(NoteConstant.PRODUCT_INDEX)
                            .id(idleProductVO.getId())
                            .doc(idleProductVO), IdleProductVO.class);
            log.info("updateResponse.result() = " + updateResponse.result());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 删除es中的笔记
     *
     * @param productId 笔记 ID
     */
    @Override
    public void deleteProduct(String productId) {
        try {
            DeleteResponse deleteResponse = elasticsearchClient
                    .delete(e -> e.index(NoteConstant.PRODUCT_INDEX).id(String.valueOf(productId)));
            log.info("deleteResponse.result() ={} ", deleteResponse.result());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
